
#include "hieth.h"
#include "mdio.h"

#include "string.h"
#include "mac.h"
#include "linux/kernel.h"
#include "hisi_mac.h"
#include "eth_drv.h"
#include "ctrl.h"
#include "eth_phy.h"
#include "eth_phy_dev.h"
#include "netdev.h"
#include "los_task.h"
#include "linux/interrupt.h"
#include "linux/timer.h"

#include "los_list.h"
#include "linux/module.h"

#define PHY_ADDR_SET     0x129B5B3
#define PHY_ADDR_NOT_SET 0x5a5aa5a5
#define INVALID_PHY_ADDR 0x12F358F
#define PHY_MODE_SET     0x12B63D0
#define PHY_MODE_NOT_SET 0x5a5aa5a5
#define INVALID_PHY_MODE 0x12F5D09

int g_user_set_phy_addr = PHY_ADDR_NOT_SET;
int g_phy_addr_val = INVALID_PHY_ADDR;
int g_user_set_phy_mode = PHY_MODE_NOT_SET;
int g_phy_mode_val = INVALID_PHY_MODE;

struct hieth_platform_data *g_stHiethPlatformData = NULL;
extern unsigned long msecs_to_jiffies(const unsigned int m);

static void _eth_drv_init(struct los_eth_driver *sc, unsigned char *mac)
{
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;

   (drv_sc->funs->eth_drv->init)(sc, mac);
}

static void _eth_drv_recv(struct los_eth_driver *sc, struct pbuf *pbuf)
{
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    struct netif *netif = &sc->ac_if;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;

    priv->rx_release++;
    if (priv->rx_release == HIETH_HWQ_RXQ_DEPTH) {
        priv->rx_release = 0;
    }

#if ETH_PAD_SIZE
    /* reclaim the padding word */
    if (pbuf_header(pbuf, ETH_PAD_SIZE)) {
        PRINTK("[HIETH_ERROR]eth_drv_recv : pbuf_header reclaim padding word failed\n");
        pbuf_free(pbuf);
        return;
    }
#endif

    net_dma_cache_inv(pbuf->payload, pbuf->tot_len);
    driverif_input(netif, pbuf);
}

HISI_NET_LOCK_T(hieth_glb_reg_lock);

void net_dma_cache_inv(void *addr, unsigned int size)
{
    unsigned int start = (unsigned int)addr & ~(CACHE_ALIGNED_SIZE - 1);
    unsigned int end = (unsigned int)addr + size;

    end = ALIGN(end, CACHE_ALIGNED_SIZE);

    dma_cache_inv(start, end);
}

void net_dma_cache_clean(void *addr, unsigned int size)
{
    unsigned int start = (unsigned int)addr & ~(CACHE_ALIGNED_SIZE - 1);
    unsigned int end = (unsigned int)addr + size;

    end = ALIGN(end, CACHE_ALIGNED_SIZE);

    dma_cache_clean(start, end);
}

static void hieth_set_mac(hieth_priv_t *priv, UINT8 *enaddr)
{
    hieth_hw_set_macaddress(&(g_stHiethPlatformData[priv->index].stNetdevLocal), 1, enaddr);
}

static void hieth_stop(struct los_eth_driver *sc)
{
}

static void hieth_start(struct los_eth_driver *sc, unsigned char *enaddr, int flags)
{
}

extern void hal_interrupt_mask(unsigned int vector);
extern int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
                       const char *name, void *dev);
extern void hal_interrupt_unmask(unsigned int vector);

void hisi_eth_isr(int irq, void *data)
{
    struct los_eth_driver *sc = (struct los_eth_driver *)data;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;

    hal_interrupt_mask(priv->intr_vector);
    LOS_EventWrite(&(g_stHiethPlatformData[priv->index].stEvent), EVENT_NET_TX_RX);
}

void hisi_eth_dsr(struct los_eth_driver *sc)
{
    UINT32 uwRet;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;

    while (1) {
        uwRet = LOS_EventRead(&(g_stHiethPlatformData[priv->index].stEvent), EVENT_NET_TX_RX,
                              LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
        if (uwRet & EVENT_NET_TX_RX) {
           (drv_sc->funs->deliver)(sc);
        }
    }
}

#define ETH_STACKSIZE 0x20000
int create_eth_irq_thread(struct los_eth_driver *sc)
{
    TSK_INIT_PARAM_S stSdTask;
    UINT32 uwRet;
    UINT32 uwEthTask;

    memset_s(&stSdTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    stSdTask.pfnTaskEntry = (TSK_ENTRY_FUNC)hisi_eth_dsr;
    stSdTask.auwArgs[0] = (UINT32)sc;
    stSdTask.uwStackSize = ETH_STACKSIZE;
    stSdTask.pcName = "eth_irq_Task";
    stSdTask.usTaskPrio = 3;
    stSdTask.uwResved = LOS_TASK_STATUS_DETACHED;
    uwRet = LOS_TaskCreate(&uwEthTask, &stSdTask);

    if (LOS_OK != uwRet) {
        return uwRet;
    }
    return 0;
}

#define PHY_ADDR 1

#define ETH_DEFAULT_MACADDR                \
    {                                      \
        0x00, 0x19, 0xb1, 0x6c, 0xa1, 0x25 \
    }

#define PHY_ID_INVALID(id) (((id & 0x1fffffff) == 0x1fffffff) ||  \
                            ((id & 0xfffffff0) == 0xfffffff0) ||  \
                            (id == 0) ||  \
                            (id == 0xffff0000) ||  \
                            (id == 0x0000ffff))

void hieth_monitor_func(unsigned long arg);
static int scan_phy_id(struct hieth_netdev_local *ld, int addr)
{
    int phy_id;
    int val;

    val = hieth_mdio_read(ld, addr, PHY_ID1);
    phy_id = val << 16;
    val = hieth_mdio_read(ld, addr, PHY_ID2);
    phy_id |= val;

    return phy_id;
}

// ===========================================================================
// This function is called for low level "control" operations
// ===========================================================================
static int hieth_control(struct los_eth_driver *sc, unsigned long key,
                         void *data, int length)
{
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    switch (key) {
        case ETH_DRV_SET_MAC_ADDRESS: {
            if (length >= ETHER_ADDR_LEN) {
                hieth_stop(sc);

                UINT8 *enaddr = (UINT8 *)data;
                PRINTK("requested MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
                       enaddr[0], enaddr[1], enaddr[2],
                       enaddr[3], enaddr[4], enaddr[5]);

                hieth_set_mac(priv, enaddr);
                hieth_start(sc, enaddr, 0);
                return 0;
            }
            return 1;
        }
        default:
        {
            diag_printf("%s.%d: key %lx\n", __FUNCTION__, __LINE__, key);
            return (1);
        }
    }  // switch (key)
}

extern int hieth_xmit_release_pkt(struct hieth_netdev_local *ld,
                                  struct los_eth_driver *sc,
                                  struct hieth_priv_s *priv);

static int hieth_can_send(struct los_eth_driver *sc)
{
    int can_send;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);
    unsigned int txq_head_next = 0;

    if (!_test_xmit_queue_ready(ld)) {
        hieth_xmit_release_pkt(ld, sc, priv);
    }

    txq_head_next = ld->txq_head + 1;
    if (txq_head_next == ld->q_size) {
        txq_head_next = 0;
    }

    HISI_NET_LOCK_GET(&(ld->tx_lock));
    if (!_test_xmit_queue_ready(ld) ||
        txq_head_next == ld->txq_tail) {
        UINT32 uwRet;
        can_send = 0;
        ld->tx_busy = 1;
        HISI_NET_LOCK_PUT(&(ld->tx_lock));
        hal_interrupt_unmask(priv->intr_vector);
        uwRet = LOS_EventRead(&(g_stHiethPlatformData[priv->index].stEvent)
                              , EVENT_NET_CAN_SEND, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, msecs_to_jiffies(40));
        if (uwRet & EVENT_NET_CAN_SEND) {
            can_send = 1;
        }
        hal_interrupt_mask(priv->intr_vector);
        HISI_NET_LOCK_GET(&(ld->tx_lock));
    } else {
        can_send = 1;
    }
    HISI_NET_LOCK_PUT(&(ld->tx_lock));

    return can_send;
}

extern int hieth_xmit_gso(struct hieth_netdev_local *ld,
                          hieth_priv_t *priv, struct pbuf *p);

static void hieth_send(struct los_eth_driver *sc, struct pbuf *p)
{
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);

    HISI_NET_LOCK_GET(&(ld->tx_lock));
    /* TSO supported */
    hieth_xmit_gso(ld, priv, p);

    ld->tx_hw_cnt++;
    HISI_NET_LOCK_PUT(&(ld->tx_lock));
}

static void hieth_deliver(struct los_eth_driver *sc)
{
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)(drv_sc->driver_private);
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);
    int ints;
    int refill_cnt = 0;
    unsigned int rx_pkt_info = 0;
    unsigned int rlen = 0;
    struct pbuf *pbuf;

    /* mask the all interrupt */
    /* Add lock for multi-processor */
    HISI_NET_LOCK_GET(&hieth_glb_reg_lock);
    hieth_writel_bits(ld, 0, GLB_RW_IRQ_ENA, BITS_IRQS_ENA_ALLPORT);
    HISI_NET_LOCK_PUT(&hieth_glb_reg_lock);

    hieth_xmit_release_pkt(ld, sc, priv);
    hieth_clear_irqstatus(ld, UD_BIT_NAME(HIETH_INT_TXQUE_RDY));

    ints = hieth_read_irqstatus(ld);

    if (ints & BITS_IRQS_MASK_U) {
        if ((ints & UD_BIT_NAME(HIETH_INT_MULTI_RXRDY))) {
            HISI_NET_LOCK_GET(&(ld->rx_lock));
            while (is_recv_packet(ld)) {
                rx_pkt_info = hw_get_rxpkg_info(ld);
                rlen = (rx_pkt_info >> BITS_RXPKG_LEN_OFFSET)
                       & BITS_RXPKG_LEN_MASK;
                rlen -= 4;
                if (rlen > HIETH_MAX_FRAME_SIZE) {
                    PRINTK("ERROR: recv len=%d\n", rlen);
                }

                HISI_NET_LOCK_GET(&hieth_glb_reg_lock);
                hw_set_rxpkg_finish(ld);
                HISI_NET_LOCK_PUT(&hieth_glb_reg_lock);

                if (priv->rx_release == priv->rx_feed) {
                    PRINTK("ERROR: rx_release=%d, rx_feed=%d\n", priv->rx_release, priv->rx_feed);
                }

                pbuf = priv->ram->rx_pbuf[priv->rx_release];
                pbuf->len = pbuf->tot_len = rlen;
                _eth_drv_recv(sc, pbuf);
            }
            HISI_NET_LOCK_PUT(&(ld->rx_lock));

            refill_cnt = hieth_feed_hw(ld, priv);
            if (!refill_cnt && (priv->rx_release == priv->rx_feed)) {
                add_timer(&priv->monitor_timer);
            }
        }
        hieth_clear_irqstatus(ld, (ints & BITS_IRQS_MASK_U));
        ints &= ~BITS_IRQS_MASK_U;
    }

    if (ints & HIETH_INT_TX_ERR_U) {
        ints &= ~HIETH_INT_TX_ERR_U;
        PRINTK("hieth_deliver: ERROR: HIETH_INT_TX_ERR_U.\n");
    }

    if (ints) {
        PRINTK("unknown ints=0x%.8x\n", ints);
        hieth_clear_irqstatus(ld, ints);
    }

    /* unmask the all interrupt */
    HISI_NET_LOCK_GET(&hieth_glb_reg_lock);
    hieth_writel_bits(ld, 1, GLB_RW_IRQ_ENA, BITS_IRQS_ENA_ALLPORT);
    HISI_NET_LOCK_PUT(&hieth_glb_reg_lock);

    hal_interrupt_unmask(priv->intr_vector);
#ifdef INT_IO_ETH_INT_SUPPORT_REQUIRED
    drv_interrupt_unmask(priv->intr_vector);
#endif
}

static void hieth_poll(struct los_eth_driver *sc)
{
    hieth_deliver(sc);
}

static int hieth_int_vector(struct los_eth_driver *sc)
{
    return NUM_HAL_INTERRUPT_ETH;
}
// just used for testsuit and demo
extern struct platform_device hieth_platform_device;
void get_defaultNetif(struct netif **pnetif)
{
    *pnetif = &(((struct los_eth_driver *)(hieth_platform_device.dev.driver_data))->ac_if);
}

// /////////////////////////////////////////////////////////////////////////////
// /used for netif
// ////////////////////////////////////////////////////////////////////////////
void eth_drv_send(struct netif *netif, struct pbuf *p);

// In platform ,this default IP is ok?
static void eth_drv_init(struct los_eth_driver *sc, unsigned char *enaddr)
{
    struct netif *netif = &sc->ac_if;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    ip4_addr_t ipaddr, netmask, gw;

    IP4_ADDR(&gw, 192, 168, 11, 1);
    IP4_ADDR(&ipaddr, 192, 168, 11, 67);
    IP4_ADDR(&netmask, 255, 255, 255, 0);
    netif->state = sc;
    netif->drv_send = eth_drv_send;
    netif->drv_set_hwaddr = hieth_set_hwaddr;
#if PF_PKT_SUPPORT
    netif->drv_config = hieth_config_mode;
#endif
#if LWIP_NETIF_ETHTOOL
    netif->ethtool_ops = NULL;
#endif
    netif->link_layer_type = ETHERNET_DRIVER_IF;
    netif->hwaddr_len = ETHARP_HWADDR_LEN;
    netif_set_default(netif_add(netif, &ipaddr, &netmask, &gw));
#if LWIP_TX_CSUM_OFFLOAD
    netif->flags |= NETIF_FLAG_DRIVER_CSUM_SUPPORT;
#endif

    // enaddr == 0 -> hardware init was incomplete (no ESA)
    if (enaddr != 0) {
        // Set up hardware address
        memcpy_s(netif->hwaddr, sizeof(netif->hwaddr), enaddr, ETHER_ADDR_LEN);
        // Perform any hardware initialization
       (drv_sc->funs->start)(sc, (unsigned char *)&netif->hwaddr, 0);
    }
    // lwip_dhcp_init(netif);

    netif_set_link_down(netif);
    netif_set_link_callback(netif, &hieth_link_status_changed);
}

void eth_drv_send(struct netif *netif, struct pbuf *p)
{
    struct los_eth_driver *sc = netif->state;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;

    hal_interrupt_mask(priv->intr_vector);

    if (!(drv_sc->funs->can_send)(sc)) {
        return;
    }

   (drv_sc->funs->send)(sc, p);

    hal_interrupt_unmask(priv->intr_vector);
}

struct los_eth_funs eth_drv_funs_hieth = { eth_drv_init, NULL, NULL };

// /////////////////////////////////////////////////////////////////////////////
// /used for netif
// ////////////////////////////////////////////////////////////////////////////
static const char *get_phy_speed_string(int speed)
{
    switch (speed) {
        case PHY_SPEED_10:
            return "10Mbps";
        case PHY_SPEED_100:
            return "100Mbps";
        case PHY_SPEED_1000:
            return "1Gbps";
        case PHY_SPEED_UNKNOWN:
            return "Unknown";
        default:
            return "Unsupported";
    }
}

void hieth_link_status_changed(struct netif *netif)
{
    struct los_eth_driver *sc = (struct los_eth_driver *)netif->state;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);
    int val = 0;

    int phy_mode = 0;
    int duplex;
    int speed;

    duplex = miiphy_duplex(ld, priv->phy);
    speed = miiphy_speed(ld, priv->phy);

    if (netif_is_link_up(netif)) {
        val |= HIETH_LINKED;
    }

    if (duplex) {
        val |= HIETH_DUP_FULL;
    }

    if (speed == PHY_SPEED_100) {
        val |= HIETH_SPD_100M;
    }

    switch (priv->phy->phy_mode) {
        case PHY_INTERFACE_MODE_MII:
            phy_mode = HIETH_PHY_MII_MODE;
            break;
        case PHY_INTERFACE_MODE_RMII:
            phy_mode = HIETH_PHY_RMII_MODE;
            break;
        default:
            PRINTK("not supported mode: %d\n", priv->phy->phy_mode);
            break;
    }

    hieth_set_linkstat(ld, val);
    hieth_set_mii_mode(ld, phy_mode);

    if (netif_is_link_up(netif))
        PRINTK("Link is Up - %s/%s\n",
               get_phy_speed_string(speed),
               PHY_DUPLEX_FULL == duplex ? "Full" : "Half");
    else {
        PRINTK("Link is Down\n");
    }
}

void phy_state_machine(unsigned long arg)
{
    struct los_eth_driver *sc = (struct los_eth_driver *)arg;
    struct netif *netif = &sc->ac_if;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);
    int link_status;

    link_status = miiphy_link(ld, priv->phy);
    if (netif_is_link_up(netif) && !link_status) {
        netif_set_link_down(netif);
    }
    else if (!netif_is_link_up(netif) && link_status) {
        netif_set_link_up(netif);
    }

    mod_timer(&priv->phy_timer, LOS_MS2Tick(PHY_STATE_TIME));
}

void hieth_monitor_func(unsigned long arg)
{
    struct los_eth_driver *sc = (struct los_eth_driver *)arg;
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)sc->driver_context;
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);
    int refill_cnt;

    refill_cnt = hieth_feed_hw(ld, priv);

    if (!refill_cnt) {
        mod_timer(&priv->monitor_timer, LOS_MS2Tick(HIETH_MONITOR_TIME));
    }
}

u8_t hieth_set_hwaddr(struct netif *netif, u8_t *addr, u8_t len)
{
    struct los_eth_driver *sc = LOS_DL_LIST_ENTRY(netif, struct los_eth_driver, ac_if);
    hieth_priv_t *priv = (hieth_priv_t *)((struct eth_drv_sc *)sc->driver_context)->driver_private;

    if (is_multicast_ether_addr(addr)) {
        PRINTK("WARN: config a muticast mac address, please check!\n");
        return -1;
    }

    if (len != ETHER_ADDR_LEN) {
        PRINTK("WARN: config wrong mac address len=%u\n", len);
        return -1;
    }

    hieth_hw_set_macaddress(&(g_stHiethPlatformData[priv->index].stNetdevLocal), 1, addr);

    memcpy_s(netif->hwaddr, sizeof(netif->hwaddr), addr, len);

    return 0;
}
#if PF_PKT_SUPPORT
void hieth_config_mode(struct netif *netif, uint32_t config_flags, u8_t setBit)
{
    struct los_eth_driver *sc = LOS_DL_LIST_ENTRY(netif, struct los_eth_driver, ac_if);
    hieth_priv_t *priv = (hieth_priv_t *)((struct eth_drv_sc *)sc->driver_context)->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);

    if (config_flags & IFF_PROMISC)
        hieth_writel_bits(ld, !!setBit, GLB_FWCTRL,
                          UD_BIT(ld->port, BITS_FWALL2CPU));
    if (config_flags & IFF_ALLMULTI)
        hieth_writel_bits(ld, !!setBit, GLB_MACTCTRL,
                          UD_BIT(ld->port, BITS_MULTI2CPU));
}
#endif

// In platform ,it may need do more things
int hisi_eth_set_phy_mode(const char *phy_mode)
{
    int i;

    for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
        if (!strcasecmp(phy_mode, phy_modes(i))) {
            g_user_set_phy_mode = PHY_MODE_SET;
            g_phy_mode_val = i;
            return 0;
        }

    return -1;
}

int hisi_eth_set_phy_addr(unsigned int phy_addr)
{
    if (phy_addr > MAX_PHY_ADDR) {
        return -1;
    }

    g_user_set_phy_addr = PHY_ADDR_SET;
    g_phy_addr_val = phy_addr;

    return 0;
}

bool hieth_hw_init(struct platform_device *dev)
{
    struct los_eth_driver *p_stDriverData = (struct los_eth_driver *)dev_get_drvdata(&(dev->dev));
    struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)(p_stDriverData->driver_context);
    hieth_priv_t *priv = (hieth_priv_t *)drv_sc->driver_private;
    struct hieth_netdev_local *ld = &(g_stHiethPlatformData[priv->index].stNetdevLocal);

    unsigned char enaddr[6] = ETH_DEFAULT_MACADDR;
    int phy_state = 0;
    unsigned int id;
    int addr;
    unsigned int data;

    HISI_NET_LOCK_INIT(&hieth_glb_reg_lock);

    ld->txq = priv->ram->txq_info;
    ld->iobase = (char *)priv->base;

    hieth_hw_mac_core_reset();

    hieth_hw_mac_core_init(ld);

    if (g_user_set_phy_mode == PHY_MODE_SET) {
        priv->phy->phy_mode = g_phy_mode_val;
        PRINTK("hisi_eth: User set phy mode=%s\n",
               phy_modes(priv->phy->phy_mode));
    } else {
        priv->phy->phy_mode = ld->phy_mode;
        PRINTK("hisi_eth: User did not set phy mode, use default=%s\n",
               phy_modes(priv->phy->phy_mode));
    }

    if (!priv->phy->init_done) {
        hieth_hw_external_phy_reset();
        mdelay(300);
        priv->phy->init_done = true;

        if (g_user_set_phy_addr == PHY_ADDR_SET) {
            priv->phy->phy_addr = g_phy_addr_val;
            PRINTK("hisi_eth: User set phy addr=%d\n", priv->phy->phy_addr);

            id = scan_phy_id(ld, priv->phy->phy_addr);
            if (PHY_ID_INVALID(id)) {
                PRINTK("Can't find PHY device - id: %x\n", id);
                priv->phy->init_done = false;
                goto err_out;
            }
        } else {
            PRINTK("hisi_eth: User did not set phy addr, auto scan...\n");

            for (addr = MAX_PHY_ADDR; addr >= 0; addr--) {
                id = scan_phy_id(ld, addr);
                if (PHY_ID_INVALID(id)) {
                    continue;
                }
                break;
            }

            if (addr < 0) {
                PRINTK("Can't find PHY device - id: %x\n", id);
                priv->phy->init_done = false;
                goto err_out;
            }

            priv->phy->phy_addr = addr;
        }
        ld->phy_id = id;
    }

    hieth_hw_external_phy_reset();
    mdelay(100);
    hieth_fephy_trim(ld, priv->phy);
    PRINTK("Detected phy addr %d, phyid: 0x%x\n", priv->phy->phy_addr, ld->phy_id);

    if (!priv->phy->init_done) {
        PRINTK("PHY state without init on PHY: %x\n", priv->phy);
        goto err_out;
    }

    hieth_get_phy_stat(ld, priv->phy, &phy_state);

    request_irq(priv->intr_vector, (irq_handler_t)hisi_eth_isr, 0, "ETH", (void *)p_stDriverData);
    hal_interrupt_unmask(priv->intr_vector);
    create_eth_irq_thread(p_stDriverData);
    eth_random_addr(enaddr);
    // Initialize the upper layer driver
    _eth_drv_init(p_stDriverData, enaddr);
    hieth_hw_set_macaddress(ld, 1, enaddr);
    // clear all interrupts
    hieth_clear_irqstatus(ld, UD_BIT_NAME(BITS_IRQS_MASK));
    priv->rx_feed = 0;
    priv->rx_release = 0;
    hieth_feed_hw(ld, priv);

    init_timer(&priv->phy_timer);
    priv->phy_timer.function = phy_state_machine;
    priv->phy_timer.data = (unsigned long)p_stDriverData;
    priv->phy_timer.expires = LOS_MS2Tick(PHY_STATE_TIME);
    add_timer(&priv->phy_timer);

    /* Use monitor_timer to refill Rx descriptor queue when refill failed */
    init_timer(&priv->monitor_timer);
    priv->monitor_timer.function = hieth_monitor_func;
    priv->monitor_timer.data = (unsigned long)p_stDriverData;
    priv->monitor_timer.expires = LOS_MS2Tick(HIETH_MONITOR_TIME);

    hieth_irq_enable(ld, UD_BIT_NAME(HIETH_INT_MULTI_RXRDY) | UD_BIT_NAME(HIETH_INT_TXQUE_RDY));
    hieth_writel_bits(ld, 1, GLB_RW_IRQ_ENA, UD_BIT_NAME(BITS_IRQS_ENA));
    hieth_writel_bits(ld, 1, GLB_RW_IRQ_ENA, BITS_IRQS_ENA_ALLPORT);
#ifdef HIETH_TSO_SUPPORTED
    hieth_irq_enable(ld, UD_BIT_NAME(HIETH_INT_TX_ERR));
#endif

    data = readl(ld->iobase + 0x210);
    data |= 0x40000000; /* do CRC check in mac */
    writel(data, ld->iobase + 0x210);
    return true;
err_out:
    return false;
}
static struct eth_hwr_funs g_stEthnetDrvFun = {
    .start = hieth_start,
    .stop = hieth_stop,
    .control = hieth_control,
    .can_send = hieth_can_send,
    .send = hieth_send,
    .recv = NULL,
    .deliver = hieth_deliver,
    .poll = hieth_poll,
    .int_vector = hieth_int_vector,
    .eth_drv = &eth_drv_funs_hieth,
    .eth_drv_old = (struct los_eth_funs *)0,

};

static int hieth_init(struct platform_device *dev)
{
    hieth_priv_t *pstPrivData = NULL;
    struct los_eth_driver *pstDrvData = NULL;
    struct eth_drv_sc *pstDrvSc = NULL;
    struct resource *res = NULL;

    // ////////////////////////////////////////////////////////
    // init drv_data, changed useful hisi_eth_drv_sc to be drv context
    // ////////////////////////////////////////////////////////

    pstPrivData = (hieth_priv_t *)malloc(sizeof(hieth_priv_t));
    if (NULL == pstPrivData) {
        hieth_error("hieth_priv_t malloc error!\n");
        return LOS_NOK;
    }

    pstPrivData->index = dev->id;
    res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
    if (NULL == res) {
        hieth_error("platform_get_resource IORESOURCE_IRQ error!\n");
        goto free_pstPrivData;
    }
    pstPrivData->intr_vector = res->start;

    res = platform_get_resource(dev, IORESOURCE_MEM, 0);
    if (NULL == res) {
        hieth_error("platform_get_resource IORESOURCE_MEM error!\n");
        goto free_pstPrivData;
    }
    pstPrivData->base = res->start;

    pstPrivData->phy = (eth_phy_access_t *)malloc(sizeof(eth_phy_access_t));
    if (NULL == pstPrivData->phy) {
        hieth_error("eth_phy_access_t malloc error!\n");
        goto free_pstPrivData;
    }

    pstPrivData->phy->init_done = false;
    pstPrivData->phy->init = NULL;
    pstPrivData->phy->reset = NULL;

    pstPrivData->ram = (eth_ram_cfg_t *)malloc(sizeof(eth_ram_cfg_t));
    if (NULL == pstPrivData->ram) {
        hieth_error("eth_ram_cfg_t malloc error!\n");
        goto free_pstPrivData_phy;
    }
    pstPrivData->ram->txq_info = zalloc(HIETH_HWQ_TXQ_SIZE * sizeof(struct tx_pkt_info));
    if (!pstPrivData->ram->txq_info) {
        hieth_error("tx_pkt_info malloc error!\n");
        goto free_pstPrivData_ram;
    }

    pstPrivData->ram->rx_pbuf = zalloc(HIETH_HWQ_RXQ_DEPTH * sizeof(struct pbuf *));
    if (!pstPrivData->ram->rx_pbuf) {
        hieth_error("pbuf malloc error!\n");
        goto free_pstPrivData_ram_txq_info;
    }

    pstPrivData->ram->dma_tx = zalloc(HIETH_HWQ_TXQ_SIZE * sizeof(struct dma_tx_desc));
    if (!pstPrivData->ram->dma_tx) {
        hieth_error("dma_tx_desc malloc error!\n");
        goto free_pstPrivData_ram_rx_pbuf;
    }

    pstPrivData->ram->pbuf_info = zalloc(HIETH_HWQ_TXQ_SIZE * sizeof(struct pbuf_info));
    if (!pstPrivData->ram->pbuf_info) {
        hieth_error("pbuf_info malloc error!\n");
        goto free_pstPrivData_ram_dma_tx;
    }

    pstDrvData = (struct los_eth_driver *)malloc(sizeof(struct los_eth_driver));
    if (NULL == pstDrvData) {
        hieth_error("los_eth_driver malloc error!\n");
        goto free_pstPrivData_ram_pbuf_info;
    }

    pstDrvSc = (struct eth_drv_sc *)malloc(sizeof(struct eth_drv_sc));
    if (NULL == pstDrvSc) {
        hieth_error("eth_drv_sc malloc error!\n");
        goto free_pstDrvData;
    }
    pstDrvSc->dev_name = "eth1";
    pstDrvSc->funs = &g_stEthnetDrvFun;
    pstDrvSc->driver_private = (void *)pstPrivData;

    pstDrvData->driver_context = (void *)pstDrvSc;
    dev->dev.driver_data = (void *)pstDrvData;
    // ////////////////////////////////////////////////////////
    // hieth_hw_init
    // ////////////////////////////////////////////////////////
    g_stHiethPlatformData = (struct hieth_platform_data *)dev_get_platdata(&(dev->dev));
    (void)LOS_EventInit(&(g_stHiethPlatformData[pstPrivData->index].stEvent));

    hieth_hw_init(dev);
    return LOS_OK;

free_pstDrvData:
    free((void *)pstDrvData);
    pstDrvData = NULL;
free_pstPrivData_ram_pbuf_info:
    free((void *)pstPrivData->ram->pbuf_info);
    pstPrivData->ram->pbuf_info = NULL;
free_pstPrivData_ram_dma_tx:
    free((void *)pstPrivData->ram->dma_tx);
    pstPrivData->ram->dma_tx = NULL;
free_pstPrivData_ram_rx_pbuf:
    free((void *)pstPrivData->ram->rx_pbuf);
    pstPrivData->ram->rx_pbuf = NULL;
free_pstPrivData_ram_txq_info:
    free((void *)pstPrivData->ram->txq_info);
    pstPrivData->ram->txq_info = NULL;
free_pstPrivData_ram:
    free((void *)pstPrivData->ram);
    pstPrivData->ram = NULL;
free_pstPrivData_phy:
    free((void *)pstPrivData->phy);
    pstPrivData->phy = NULL;
free_pstPrivData:
    free((void *)pstPrivData);
    pstPrivData = NULL;
    return LOS_NOK;
}

static int ethnet_hieth_suspend(struct device *dev)
{
    //struct platform_device *pdev = to_platform_device(dev);
    return 0;
}

static int ethnet_hieth_resume(struct device *dev)
{
    //struct platform_device *pdev = to_platform_device(dev);
    return 0;
}

static const struct dev_pm_op ethnet_hieth_dev_pm_ops = {
    .suspend = ethnet_hieth_suspend,
    .resume = ethnet_hieth_resume,
};

static int ethnet_hieth_probe(struct platform_device *dev)
{
    return hieth_init(dev);
}

static int ethnet_hieth_remove(struct platform_device *dev)
{
    return 0;
}

static struct platform_driver hieth_platform_driver = {
    .probe = ethnet_hieth_probe,
    .remove = ethnet_hieth_remove,
    .driver = {
        .name = HIETH_DRIVER_NAME,
        .pm = &ethnet_hieth_dev_pm_ops,
    },
};

int /* __init */ ethnet_hieth_init(void)
{
    int ret = 0;
    ret = platform_driver_register(&hieth_platform_driver);
    if (ret) {
        hieth_error("register platform driver failed!");
        return LOS_NOK;
    }

    return ret;
}

void /* __exit */ ethnet_hieth_exit(void)
{
    platform_driver_unregister(&hieth_platform_driver);
}

module_init(ethnet_hieth_init);
module_exit(ethnet_hieth_exit);
